package Data;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import strategies.Strategy;


/**
 * singelton that connect with the hibernate - DB
 * 
 * @author Vladimir Sarkisyan & Erez Levy
 *
 */
public class HibernateUtil {

	SessionFactory sessionFactory ;
	Session session;
	FileManager fileManager;
	TagManager tagManager;
	
	public static HibernateUtil instance = new HibernateUtil(); 
	
	private HibernateUtil(){
		
		 sessionFactory = new Configuration().configure().buildSessionFactory(); 
		 session = sessionFactory.openSession();
		 fileManager = new FileManager(session);
		 tagManager = new TagManager(session);
	}
	
	/**
	 * save the file in the DB
	 * 
	 * the function get a file check that he is not exist in
	 * the DB and save it
	 * 
	 * @param file - from type file
	 */
	public void saveFile(FileData file){
		//check if the file don't exist
		SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); 
		Session session2 = sessionFactory.openSession();
		
		String fileName = file.getName();
		String tag  = file.getTag();
		
		Query q = session2.createQuery("from FileData f where f.name Like :fileName and f.tag Like :tag"); 
		q.setParameter("fileName", fileName);
		q.setParameter("tag", tag);
		
		List list =  q.list();
        
		//if the file don't exist
        if(list.size() == 0){		 
        	SessionFactory sessionFactory2 = new Configuration().configure().buildSessionFactory(); 
        	Session session22 = sessionFactory2.openSession();

        	System.out.println("HibernateUtil - saveFile");
        	//fileManager.saveFile(file);
			//for debugging
        	session22.save(file);
			System.out.println("File saved with ID = "+ file.getFileId());
	
			session22.flush();
        }
	}
	
	
	/**
	 * the function get array of files and save them in the DB
	 * 
	 * @param fileList - ArrayList of files
	 */
	public void saveFile(ArrayList<FileData> fileList){
		SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); 
		Session session = sessionFactory.openSession();
		
		for(int i=0; i<fileList.size(); i++){
			 session.save(fileList.get(i));
			 session.flush();
		 }
	}
	

	/**
	 * the function update the file in the DB
	 * 
	 * @param file
	 */
	public void updateFile(FileData file){
		  session.update(file);
		  session.flush();
	}
	
	
	/**
	 * checking if the file exist in the DB
	 * 
	 * @param fileName - string of the file
	 * @return boolean 
	 */
	
	public boolean fileExist(String fileName){
		System.out.println("HibernateUtil -  fileExist");
		SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); 
		Session session = sessionFactory.openSession();
    	String tag = "global@global";
		
		//check if the file dont exist
		Query q = session.createQuery("from FileData f where f.name Like :fileName and f.tag Like :tag"); 
		q.setString("fileName", fileName);
		q.setString("tag", tag);
		
		List list =  q.list();
		
		System.out.println("HibernateUtil  list.size: " + list.size());
		if(list.size()!=0){
			return true;
		}
		else{
			return false;
		}
	}
	
	/**
	 * delete a file from DB
	 * 
	 * @param fileName - string of the file
	 */
	public void deleteFile(String  fileName) {		
		SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); 
		Session session = sessionFactory.openSession();
		
		Query q = session.createQuery("delete FileData f where f.name Like :fileName"); 
		q.setParameter("fileName", fileName);
		q.executeUpdate();
	} 
		 
	
	/**
	 * remove tuples from the DB with some strategy
	 * 
	 * @param strategyName
	 */
	public void deleteFilesWithSomeStrategy(String strategyName) {		
		SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); 
		Session session = sessionFactory.openSession();
		
		Query q = session.createQuery("delete FileData f where f.strategy Like :strategyName"); 
		q.setParameter("strategyName", strategyName);
		q.executeUpdate();
	} 
			
		 
	/**
	 * rename the name of the file in the DB
	 * 
	 * the function create a new tuples for the new name
	 *  accordingly to the old , and the tuples with old
	 *  name are deleted 
	 * 
	 * @param oldName
	 * @param newName
	 */
	public void renameFile(String  oldName,String newName) {		
		SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); 
		Session session = sessionFactory.openSession();
		//for debug 
		System.out.println("in HibernateUtil-renameFile");
		//		
		//save all the files
		Query q = getFilesByName(oldName);
		List list =  q.list();		
	
		//list for the files; 
		ArrayList<FileData> fileList = new ArrayList<FileData>();
		
		
		Iterator files = list.iterator();
		while(files.hasNext()) { 
			FileData fileData = (FileData)files.next(); 
			//for debug 
			System.out.println(newName+ "       tag: " + fileData.getTag());
			//	
			//set an new fileData
			FileData fileData2 = new FileData(newName, fileData.getTag(), fileData.getStrategy(), fileData.isStrategyTag());
			//add to the list
			fileList.add(fileData2);
		} 
		
		//save the new files in the DB
		saveFile(fileList);	
		
		//delete the files from the DB
		deleteFile(oldName);
	} 
	
	
	
	/**
	 * return Query of files that have the name: fileName
	 * 
	 * @param fileName - string of the name
	 * @return - Query with files with the same name like fileName
	 */
	public Query getFilesByName(String fileName){
		SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); 
		Session session = sessionFactory.openSession();
		
		Query q = session.createQuery("from FileData f where f.name Like :fileName"); 
		q.setString("fileName", fileName);	
		return q;	
	}
	
	
	
	/**
	 * return all the tuples with this tag
	 * should be use for user tags
	 * 
	 * @param userTag - name of the tag
	 */
	public ArrayList<String> getFilesByTag(String userTag){
		SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); 
		Session session = sessionFactory.openSession();
		
		Query q = session.createQuery("from FileData f where f.tag Like :userTag"); 
		q.setString("userTag", userTag);
		
		//list for the files; 
		ArrayList<String> fileList = new ArrayList<String>();		
		//iterator
		List list =  q.list();
		Iterator files = list.iterator();
		
		while(files.hasNext()) { 
			FileData fileData = (FileData)files.next(); 			
			//add to the list
			fileList.add(fileData.getName());
		} 
				
		return fileList;	
	}
	//end of getFilesByTag
	
	
	/**
	 * save the tag in the DB
	 * 
	 * @param tag - from type Tag
	 */
	public void saveTag(Tag tag){
		//for debug 
		System.out.println("in HibernateUtil-saveTag");
		//	
		SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); 
		Session session = sessionFactory.openSession();
		
		String name = tag.getName();
		//check that the tag does not exist
		Query q = session.createQuery("from Tag t where t.name Like :name"); 
		q.setString("name", name);
		
		List list =  q.list();
		System.out.println("list size = " + list.size());
		//in case the file with this tag don't exist --> save in the DB
		if(list.size()==0){
			session.save(tag);
			//for debugging
			System.out.println("tag saved with ID = "+ tag.getTagId());
			session.flush();	
		}
	}
	
	
    /**
     * the function get name of a file and tag, and tag this file
     * 
     * check that not exist and after that tag it - create a new 
     * tuple with the file name, and the tag name
     * 
     * @param fileName
     * @param tag
     */
    public void tagFileByUserTag(String fileName, String tag){
		SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); 
		Session session = sessionFactory.openSession();
    	
		//check if the file dont exist
		Query q = session.createQuery("from FileData f where f.name Like :fileName and f.tag Like :tag"); 
		q.setString("fileName", fileName);
		q.setString("tag", tag);
		
		List list =  q.list();
		//in case the file with this tag dont exist
		if(list.size()==0){
			//from User u where u.lastName Like :lastName and u.firstName Like :firstName
			FileData fileData = new FileData(fileName, tag, null, 0);
			//save the file
			session.save(fileData);
			session.flush();
		} 	
    }
    //end of tagFileByUserTag

    
    
    /**
     * The function get a strategy and tag all the files by this strategy
     * 
     * The function get all the files with the tag - "global@global"  , that means 
     * all the files in the DB, and create a new tuple for every one of them with 
     * one of the tags from the strategy
     * 
     * @param strategyInstance - from type Strategy
     */
    public void tagByStrategyAllTheFiles(Strategy strategyInstance){
		SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); 
		Session session = sessionFactory.openSession();
		//for debuging 
		/*System.out.println("in HibernateUtil - tagByStrategyAllTheFiles");
		SessionFactory sessionFactory2 = new Configuration().configure().buildSessionFactory(); 
		Session session2 = sessionFactory2.openSession();
		FileData f = new FileData("test", "global@global", null, 0);
		saveFile(f);
		*/		
		//
		
    	String global = "global@global"; 
    	//go over the all files - all the files in the DB that  
    	Query q = session.createQuery("from FileData f where f.tag Like :global"); 
    	q.setString("global", global);
    	System.out.println("after Query");
    	
    	List list =  q.list();
    	System.out.println("size: " + list.size());
    	Iterator files = list.iterator();
    	
    	while(files.hasNext()) { 
    		//get the file
    		FileData fileData = (FileData)files.next(); 
    		//tag the file 
    		tagFileByStrategy(fileData.getName(), strategyInstance);    		
    	} 
    }
    


    
    /**
     * The function tag a file by some Strategy
     * 
     * The function get a file name and Strategy, check that
     * the file don't tagged by this Strategy, and after that
     * tag the file by this Strategy - create a new tuple in 
     * the DB 
     * 
     * @param fileName
     * @param strategyInstance - from type Strategy
     */
    public void tagFileByStrategy(String fileName, Strategy strategyInstance){
    	
    	//first check if the file not taged by the strategy
		SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); 
		Session session = sessionFactory.openSession();
    	String strategy = strategyInstance.getStrategyName();
    	
		//for debuging 
		System.out.println("in HibernateUtil - tagFileByStrategy");
		System.out.println("fileName: " + fileName);
		System.out.println("strategy: " + strategy);
		//
		//check if the file dont exist
		Query q = session.createQuery("from FileData f where f.name Like :fileName and f.strategy Like :strategy"); 
		q.setString("fileName", fileName);
		q.setString("strategy", strategy);
		
		List list =  q.list();
		//in case the file not taged by this strategy
		if(list.size()==0){
			//for debuging 
			System.out.println("the file not taged --> tag it");
			//
			//get the file tag for the strategy
			String tag  = strategyInstance.tag(fileName);
			
			//for debuging 
			System.out.println("tag - " + tag);
			//
            //create a new file
            FileData file = new FileData(fileName, tag, strategyInstance.getStrategyName(), 1);
			session.save(file);
			session.flush();
		}   	
    }
    
    /**
     * the function get strategyName and his tag and return all the files with this tag
     * 
     * @param strategyName - the name of the strategy
     * @param tag - name of the tag
     * @return filesNames - list of names of the files 
     */
    public ArrayList<String> searchFilesByStrategy(String strategyName, String tag) {
		SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); 
		Session session = sessionFactory.openSession();    
    	
    	ArrayList<String> filesNames = new ArrayList<String>();
		
    	Query q = session.createQuery("from FileData f where f.strategy Like :strategyName and f.tag Like :tag"); 
		q.setString("strategyName", strategyName);
		q.setString("tag", tag);                    
          
		List list =  q.list();
		//in case the file with this tag dont exist
		Iterator files = list.iterator();
		while(files.hasNext()) { 
			FileData fileData = (FileData)files.next(); 
			//add to the list
			filesNames.add(fileData.getName());
		} 
 	
		
        return filesNames;
    }
    //end searchFilesByStrateg
    
    
	/**
	 * update the Tag in the DB
	 */
	public void updateTag(Tag tag){
		  session.update(tag);
		  session.flush();
	}
	
	/**
	 * delete  Tag in the DB
	 */
	public void deleteTag(Tag tag) {
		  session.delete(tag);
		  session.flush();
	}
		
}
